package com.rm.vip;

import com.rm.vip.request.RequestData;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @ProjectName: vip-rpc-parent
 * @Auther: GERRY
 * @Date: 2019/1/15 21:45
 * @Description:
 */
public class RpcServer {

    private final int port;
    private Map<String , Object> servicesList = new ConcurrentHashMap<>(16);
    private ThreadPoolExecutor
            executor = new ThreadPoolExecutor(4,
            20, 1000, TimeUnit.MILLISECONDS,
            new ArrayBlockingQueue<>(10));


    public RpcServer(int port) {
        this.port = port;
    }

    /**
     * 暴露服务的接口的方法
     * @param interfaceClass
     * @param instance
     */
    public void publishServer(Class<?> interfaceClass, Object instance) {
        this.servicesList.put(interfaceClass.getName(), instance);
    }

    public void start() {
        try {
            ServerSocket serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress(port));
            System.out.println("--gerry dubbo starting--");
            while (true) {
                executor.execute(new ServerTask(serverSocket.accept()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private class ServerTask implements Runnable {

        private final Socket socket;

        public ServerTask(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try (
                    ObjectInputStream deSerializer = new ObjectInputStream(socket.getInputStream());
                    ObjectOutputStream serializer = new ObjectOutputStream(socket.getOutputStream())
                 ){
                // 反序列获取客户端传入数据
                RequestData requestData = (RequestData) deSerializer.readObject();
                // 解析对应服务接口名称
                String interfaceName = requestData.getInterfaceName();
                if (!servicesList.containsKey(interfaceName)) {
                    throw new RuntimeException("你调用服务接口没有找到对应实现类的实例");
                }
                Object instance = servicesList.get(interfaceName);
                // 通过放射创建调用的方法对象
                Method method =
                        instance.getClass()
                                .getDeclaredMethod(requestData.getMethodName(), requestData.getParameterTypes());
                // 通过反射调用对应方法并获取返回值
                Object result = method.invoke(instance, requestData.getParameters());

                // 序列化到流中
                serializer.writeObject(result);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
